package com.gitee.loyo.jdbc

import com.gitee.loyo.KSQL
import com.gitee.loyo.Utils
import com.gitee.loyo.interfaces.LazyReadMapper
import com.gitee.loyo.interfaces.TypeReference
import java.sql.ResultSet
import kotlin.reflect.KClass

open class Rs(private val rs: ResultSet) : ResultSet by rs, LazyReadMapper {
    private var closeListener: (() -> Unit)? = null

    open fun asInt(): Int{
        return `as`()?:0
    }

    inline fun <reified T: Any> `as`(): T?{
        val result = asList(object : TypeReference<T>(){})
        if(KSQL.strictOneRow && result.size > 1){
            throw RuntimeException("返回结果大于1行")
        }
        return result.firstOrNull()
    }

    override fun <T: Any> `as`(kType: KClass<T>): T? {
        val result = asList(kType)
        if(KSQL.strictOneRow && result.size > 1){
            throw RuntimeException("返回结果大于1行")
        }
        return result.firstOrNull()
    }

    override fun <T : Any> `as`(typeRef: TypeReference<T>): T? {
        val result = asList(typeRef)
        if(KSQL.strictOneRow && result.size > 1){
            throw RuntimeException("返回结果大于1行")
        }
        return result.firstOrNull()
    }

    inline fun <reified T: Any> asList(): List<T>{
        return asList(object : TypeReference<T>(){})
    }

    override fun <T: Any> asList(kType: KClass<T>): List<T>{
        return this.use {
            KSQL.resultSetHandler.handle(rs, object : TypeReference<T>(kType.java){}.apply {}) as List<T>
        }
    }

    override fun <T: Any> asList(typeRef: TypeReference<T>): List<T>{
        return this.use {
            KSQL.resultSetHandler.handle(rs, typeRef) as List<T>
        }
    }

    fun getGeneratedKey(): Any? {
        this.use {
            if(rs.next()){
                val metadata = rs.metaData
                val type = Utils.toClass(metadata.getColumnType(1))
                val resultSetHandler = JDBC.resultSetHandlerMap[type]
                    ?: throw RuntimeException("未找到" + type.qualifiedName + ", 请使用JDBC.putResultSetHandler添加相应类型处理")
                return resultSetHandler.handle(rs, 1)
            }
            return null
        }
    }

    fun setCloseListener(closeListener: () -> Unit): Rs{
        this.closeListener = closeListener
        return this
    }

    override fun close() {
        rs.close()
        closeListener?.invoke()
    }
}